#include "stdafx.h"

#include "WinLock.h"
#include "ckfifo.h"

#include <algorithm>

#define power_of_2b(x)  (            (x) | (            (x) >> 1))
#define power_of_4b(x)  ( power_of_2b(x) | ( power_of_2b(x) >> 2))
#define power_of_8b(x)  ( power_of_4b(x) | ( power_of_4b(x) >> 4))
#define power_of_16b(x) ( power_of_8b(x) | ( power_of_8b(x) >> 8))
#define power_of_32b(x) (power_of_16b(x) | (power_of_16b(x) >> 16))

unsigned int ckfifo::roundpower_of_2(unsigned int len)
{
	return (len > 0 ? power_of_32b(len - 1) + 1 : 8);
}

ckfifo::ckfifo(unsigned int size) : m_buf(0), m_in(0), m_out(0)
{
	m_size = roundpower_of_2(size);
}

ckfifo::~ckfifo()
{
	if(m_buf)
	{
		delete [] m_buf;
		m_buf = NULL;
	}
}

bool ckfifo::init()
{
	m_buf = new unsigned char[m_size];
	if(NULL == m_buf) return false;

	m_in = m_out = 0;

	return true;
}

unsigned int ckfifo::fifo_get(unsigned char *buf, unsigned int len)
{
	WinLock::ScopeLock tlock(m_lock);

	unsigned int l;

	len = (std::min)(len, m_in - m_out); 

	l = (std::min)(len, m_size - (m_out & (m_size - 1)));
	memcpy(buf, m_buf + (m_out & (m_size - 1)), l);
	memcpy(buf + l, m_buf, len - l);

	m_out += len;

	return len;
}

unsigned int ckfifo::fifo_put(const unsigned char *buf, unsigned int len)
{
	WinLock::ScopeLock tlock(m_lock);

	unsigned int l;

	len = (std::min)(len, m_size - m_in + m_out);

	l = (std::min)(len, m_size - (m_in & (m_size - 1)));
	memcpy(m_buf + (m_in & (m_size - 1)), buf, l);
	memcpy(m_buf, buf + l, len -l);

	m_in += len;

	return len;
}
